ホームに戻る
出典 :
関連 :
目次 :

ウィンドウを表示する手段

ウィンドウ( System.Windows.Window 、およびその派生クラス)はインスタンスが生成された時点では表示されず、 Show() または ShowDialog() メソッドを呼び出すなどで明示的に表示させる必要がある。
Window.Show() ウィンドウをモードレスウィンドウとして開く。
(開くと呼び元に制御を戻し、閉じるのを待機しない。)
Window.ShowDialog() ウィンドウをモーダルウィンドウとして開く。
(ウィンドウが閉じるまで呼び元に制御を戻さない。)

Show() に関する補足

Show() を呼び出すことは Window の Visibility を Visible に変更することと最終結果は変わらない。 即ち、Visibility を Visible に変更することでもモードレスウィンドウとして表示させることができるが、その振る舞いは Show() とは微妙に異なる。
Show() を呼び出す場合の例
private void DoSomething01() { // ウィンドウ生成 Window w = new Window(); // Loaded イベントのハンドラを登録 w.Loaded += delegate { System.Console.WriteLine("こちらが「先」に実行されます。"); }; // 表示( Show() 実行) w.Show(); System.Console.WriteLine("こちらが「後」に実行されます。"); }
Visibility を変更する場合の例
private void DoSomething02() { // ウィンドウ生成 Window w = new Window(); // Loaded イベントのハンドラを登録 w.Loaded += delegate { System.Console.WriteLine("こちらが「後」に実行されるかもしれません。"); }; // 表示( Visibility 変更) w.Visibility = Visibility.Visible; System.Console.WriteLine("こちらが「先」に実行されるかもしれません。"); }
Console.WriteLine() の内容に注意されたい。これらは当該行の処理順を表している。 DoSomething01() 内で実行される Window.Show() は、新しく開かれた Window の Loaded イベントの発生(およびイベントハンドラ実行)後まで制御が戻らない(同期実行)。 しかし、DoSomething02() では Visibility の変更後即座に制御が戻る(非同期実行)ため、Loaded イベントの発生が DoSomething02() の実行後となる可能性がある(実行順が保証されない)。

実行結果( Window.DialogResult )

ShowDialog() の戻り値として返される(モーダル)ウィンドウの実行結果。プロパティとして取得、設定が可能である。 Nullable<Boolean> として宣言されており、既定値は false である。 設定には制約があり、以下の場合は InvalidOperationException 例外が発行される。
(Windows Formsではモードレスでも DialogResult が設定・取得可能であり、とり得る値も異なる。)

オーナーウィンドウの設定(Window.Owner)

ウィンドウをモーダル表示した場合、新たに開くウィンドウと呼び元の(イベントハンドラを持つ)ウィンドウとは自動的には関連付けられない。 そうした場合、例えばタスクバーから呼び元のウィンドウを選択すると、そのウィンドウがアクティブとなってしまう。 (モーダル表示されているウィンドウが存在するため、操作はできない。) このような現象を避けるには ShowDialog() を呼び出す前に、表示するウィンドウの Owner を明示的に指定する。 (Windows Formsでは自動的にオーナーが設定される点が異なる。)
// ボタン押下時の処理 // 新しいウィンドウを開く private void Button_Click(object sender, RoutedEventArgs e) { // ウィンドウの生成・プロパティ設定 var wnd = new Window(); wnd.Title = "dynamic window #1"; wnd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner; wnd.Width = this.Width / 2; wnd.Height = this.Height / 2; // 新しいウィンドウの Owner を自身に指定する wnd.Owner = this; // ウィンドウを開く wnd.ShowDialog(); }

現在アクティブなウィンドウを取得する方法

現在アクティブなウィンドウを取得する場合は、以下のように記述する(C#とLINQを使用)。 ここで、Application および Window はともに System.Windows 名前空間に属する。
var activeWindow = Application.Current.Windows .OfType<Window>() .SingleOrDefault(x => x.IsActive);

ウィンドウの表示に関するプロパティ

プロパティを操作することで、ウィンドウの外見や動作を変更することができる。詳細はリンク先を参照。

UIスレッドからモードレスウィンドウを開く場合の注意点

UIスレッド(UIイベントハンドラ)からウィンドウをモードレスで開く場合、実装によってはウィンドウが表示されない。
正しくないコード
// ボタンクリックハンドラ private void Button_Click( object sender, RoutedEventArgs e ) { try { // 処理中表示(モードレス) WaitingScreen waiting = new ( "しばらくお待ちください…" ); waiting.Owner = this; waiting.Show(); // (時間のかかる処理) Task.Run( () => HeavyTask() ).Wait(); // 待機画面を閉じる waiting.Close(); } catch( Exception ex ) { : } }
上記のコードでは、ボタンクリックを契機に時間のかかる処理を行い、その際に処理中である旨をモードレスウィンドウで表示しようとしている。 注意が必要な点として、Window.Show() によるモードレス表示はUIスレッドの終了後に行われることがあげられる。 (ウィンドウが表示されるためには、一旦呼び元に制御が戻る必要がある。) ここでは HeavyTask() の終了を Task.Wait() で待機していることでUIスレッド( Button_Click() )がブロックされ、モードレスウィンドウが表示されない。
修正したコード
// ボタンクリックハンドラ( async ) private async void Button_Click( object sender, RoutedEventArgs e ) { try { // 処理中表示(モードレス) WaitingScreen waiting = new ( "しばらくお待ちください…" ); waiting.Owner = this; waiting.Show(); // (時間のかかる処理 : await で待機) await Task.Run( () => HeavyTask() ); // 待機画面を閉じる waiting.Close(); } catch( Exception ex ) { : } }
Task.Wait() を await に置き換えている。 これにより、await に遭遇した時点で一旦UIスレッドが終了するため、想定通りの順序で処理が行われる。